home *** CD-ROM | disk | FTP | other *** search
/ Sun Solutions 1997 April to September / Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso / products / bin / httpd / src / http_log.c < prev    next >
C/C++ Source or Header  |  1995-05-18  |  13KB  |  438 lines

  1. /*
  2.  * http_log.c: Dealing with the logs and errors
  3.  * 
  4.  * All code contained herein is covered by the Copyright as distributed
  5.  * in the README file in the main directory of the distribution of 
  6.  * NCSA HTTPD.
  7.  *
  8.  * Based on NCSA HTTPd 1.3 by Rob McCool
  9.  * 
  10.  * 10/28/94 cvarela
  11.  *    Added agent_log and referer_log files.
  12.  *
  13.  * 02/15/95 blong
  14.  *    Added support for configuration defined error messages
  15.  * 
  16.  * 03/19/95 blong
  17.  *    Some modification to status lines for uniformity, and for user
  18.  *    defined error messages to give the correct status.
  19.  *
  20.  * 04/11/95 blong
  21.  *    Changed custom error responses to only send the error string as
  22.  *    arguments to the script
  23.  *
  24.  * 05/08/95 blong
  25.  *    Bowing to pressure, added patch by Paul Phillips (paulp@cerf.net)
  26.  *    to set CLOSE_ON_EXEC flag for log files under #define SECURE_LOGS
  27.  */
  28.  
  29.  
  30. #include "httpd.h"
  31. #include "new.h"
  32.  
  33. const char StatLine200[] = "200 Document follows";
  34. const char StatLine302[] = "302 Found";
  35. const char StatLine304[] = "304 Not modified";
  36. const char StatLine400[] = "400 Bad Request";
  37. const char StatLine401[] = "401 Unauthorized";
  38. const char StatLine403[] = "403 Forbidden";
  39. const char StatLine404[] = "404 Not Found";
  40. const char StatLine500[] = "500 Server Error";
  41. const char StatLine501[] = "501 Not Implemented";
  42.  
  43. /* Moved to http_request.c */
  44. /* static char the_request[HUGE_STRING_LEN]; */
  45. extern char the_request[HUGE_STRING_LEN];
  46. int status;
  47. int bytes_sent;
  48.  
  49. FILE *error_log;
  50. /* static FILE *xfer_log; */
  51. static int xfer_log;
  52. static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT );
  53. static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
  54. FILE *agent_log;
  55. FILE *referer_log;
  56. int ErrorStat=0;
  57. ErrorMessage Errors[NUM_ERRORS];
  58. int numErrorsDefined=0;
  59. extern int servernum;
  60. extern char referer[];
  61. extern char *save_name;
  62.  
  63. void open_logs() {
  64.     int flags;
  65.     if(!(error_log = fopen(error_fname,"a"))) {
  66.         fprintf(stderr,"httpd: could not open error log file %s.\n",
  67.                 error_fname);
  68.         perror("fopen");
  69.         exit(1);
  70.     }
  71.     if((xfer_log = open(xfer_fname,xfer_flags,xfer_mode)) < 0) {
  72.         fprintf(stderr,"httpd: could not open transfer log file %s.\n",
  73.                 xfer_fname);
  74.         perror("open");
  75.         exit(1);
  76.     }
  77.     if(!(agent_log = fopen(agent_fname,"a"))) {
  78.         fprintf(stderr,"httpd: could not open agent log file %s.\n",
  79.                 agent_fname);
  80.         perror("fopen");
  81.         exit(1);
  82.     }
  83.     if(!(referer_log = fopen(referer_fname,"a"))) {
  84.         fprintf(stderr,"httpd: could not open referer log file %s.\n",
  85.                 referer_fname);
  86.         perror("fopen");
  87.         exit(1);
  88.     }
  89.    
  90. #ifdef SECURE_LOGS
  91.     /* set close-on-exec flag so CGI's cannot get to logs */
  92.     flags = fcntl(xfer_log, F_GETFD);
  93.     flags |= FD_CLOEXEC;
  94.     fcntl(xfer_log, F_SETFD, flags);
  95.     flags = fcntl(fileno(agent_log), F_GETFD);
  96.     flags |= FD_CLOEXEC;
  97.     fcntl(fileno(agent_log), F_SETFD, flags);
  98.     flags = fcntl(fileno(referer_log), F_GETFD);
  99.     flags |= FD_CLOEXEC;
  100.     fcntl(fileno(referer_log), F_SETFD, flags);
  101. #endif /* SECURE_LOGS */
  102. }
  103.  
  104. void close_logs() {
  105.     fflush(error_log);
  106.     fflush(agent_log);
  107.     fflush(referer_log);
  108.     close(xfer_log);
  109.     fclose(error_log);
  110.     fclose(agent_log);
  111.     fclose(referer_log);
  112. }
  113.  
  114. void error_log2stderr() {
  115.     if(fileno(error_log) != STDERR_FILENO)
  116.         dup2(fileno(error_log),STDERR_FILENO);
  117. }
  118.  
  119. void log_pid() {
  120.     FILE *pid_file;
  121.  
  122.     if(!(pid_file = fopen(pid_fname,"w"))) {
  123.         fprintf(stderr,"httpd: could not log pid to file %s\n",pid_fname);
  124.         exit(1);
  125.     }
  126.     fprintf(pid_file,"%d\n",getpid());
  127.     fclose(pid_file);
  128. }
  129.  
  130. /*
  131. void record_request(char *cmd_line) {
  132.     bytes_sent = -1;
  133.  
  134.     strcpy(the_request,cmd_line);
  135. }
  136. */
  137.  
  138. void log_transaction() {
  139.     char str[HUGE_STRING_LEN];
  140.     long timz;
  141.     struct tm *t;
  142.     char tstr[MAX_STRING_LEN],sign;
  143.  
  144.     t = get_gmtoff(&timz);
  145.     sign = (timz < 0 ? '-' : '+');
  146.     if(timz < 0) 
  147.         timz = -timz;
  148.  
  149.     strftime(tstr,MAX_STRING_LEN,"%d/%b/%Y:%H:%M:%S",t);
  150.     sprintf(str,"%s %s %s [%s %c%02d%02d] \"%s\" ",
  151.             remote_name,
  152.             (do_rfc931 ? remote_logname : "-"),
  153.             (user[0] ? user : "-"),
  154.             tstr,
  155.             sign,
  156.             timz/3600,
  157.             timz%3600,
  158.             the_request); 
  159.     if(status != -1)
  160.         sprintf(str,"%s%d ",str,status);
  161.     else
  162.         strcat(str,"- ");
  163.  
  164.     if(bytes_sent != -1)
  165.         sprintf(str,"%s%d\n",str,bytes_sent);
  166.     else
  167.         strcat(str,"-\n");
  168. /*    sprintf(str,"%s SN:%d",str,servernum);
  169.     fprintf(xfer_log,"%s\n",str);
  170.     fflush(xfer_log); */
  171.     write(xfer_log,str,strlen(str));
  172. }
  173.  
  174. void log_error(char *err) {
  175.     fprintf(error_log, "[%s] %s\n",get_time(),err);
  176.     fflush(error_log);
  177. }
  178.  
  179. void log_error_noclose(char *err) {
  180.     fprintf(error_log, "[%s] %s\n",get_time(),err);
  181.     fflush(error_log);
  182. }
  183.  
  184. void log_reason(char *reason, char *file) {
  185.     char *buffer;
  186.  
  187.     buffer = (char *)malloc(strlen(reason)+strlen(referer)+strlen(remote_name)+
  188.                 strlen(file)+50); 
  189.     sprintf(buffer,"httpd: access to %s failed for %s, reason: %s from %s",
  190.             file,remote_name,reason,( (referer[0] != '\0') ? referer : "-"));
  191.     log_error(buffer);
  192.     free(buffer);
  193. }
  194.  
  195. void begin_http_header(FILE *fd, const char *msg) {
  196.     fprintf(fd,"%s %s%c",SERVER_PROTOCOL,msg,LF);
  197.     dump_default_header(fd);
  198. }
  199.  
  200. void error_head(FILE *fd, const char *err) {
  201.     if(!assbackwards) {
  202.         begin_http_header(fd,err);
  203.         fprintf(fd,"Content-type: text/html%c%c",LF,LF);
  204.     }
  205.     if(!header_only) {
  206.         fprintf(fd,"<HEAD><TITLE>%s</TITLE></HEAD>%c",err,LF);
  207.         fprintf(fd,"<BODY><H1>%s</H1>%c",err,LF);
  208.     }
  209. }
  210.  
  211. void title_html(FILE *fd, char *msg) {
  212.     fprintf(fd,"<HEAD><TITLE>%s</TITLE></HEAD>%c",msg,LF);
  213.     fprintf(fd,"<BODY><H1>%s</H1>%c",msg,LF);
  214. }
  215.  
  216. int die(int type, char *err_string, FILE *fd) {
  217.     char error_doc[MAX_STRING_LEN];
  218.     char arguments[HUGE_STRING_LEN];
  219.     int RetVal=0;
  220.     int x;
  221.  
  222.     /* For custom error scripts */
  223.     strcpy(failed_request,the_request);
  224.     strcpy(failed_url,url2);
  225.  
  226.     /* For 1.4b4, changed to have a common message for ErrorDocument calls
  227.        We now send only error=err_string (as passed) and the CGI environment
  228.        variable ERROR_STATUS,ERROR_REQUEST,ERROR_URL contain the rest of the
  229.        relevent information */
  230.  
  231.     if (err_string)
  232.       sprintf(arguments,"error=%s",err_string);
  233.  
  234.     switch(type) {
  235.       case REDIRECT:
  236.         status = 302;
  237.     if (((x=have_error(type)) >= 0) && (!ErrorStat)) {
  238.         ErrorStat = status;
  239.         strcpy(error_doc,Errors[x].ErrorFile);
  240.         process_get(0,fd,"GET",error_doc,arguments);
  241.     } else {
  242.         if(!assbackwards) {
  243.         begin_http_header(fd,StatLine302);
  244.         fprintf(fd,"Location: %s%c",err_string,LF);
  245.         fprintf(fd,"Content-type: text/html%c",LF);
  246.         fputc(LF,fd);
  247.         }
  248.         if(header_only) break;
  249.         title_html(fd,"Document moved");
  250.         fprintf(fd,"This document has moved <A HREF=\"%s\">here</A>.<P>%c",
  251.             err_string,LF);
  252.             fprintf(fd,"</BODY>%c",LF);
  253.     }
  254.         break;
  255.       case USE_LOCAL_COPY:
  256.         status = USE_LOCAL_COPY;
  257.         begin_http_header(fd,StatLine304);
  258.         fputc(LF,fd);
  259.         header_only = 1;
  260.     RetVal = USE_LOCAL_COPY;
  261.         break;
  262.       case AUTH_REQUIRED:
  263.         status = 401;
  264.     if (((x=have_error(type)) >= 0) && (!ErrorStat)) {
  265.         ErrorStat = status;
  266.         strcpy(error_doc,Errors[x].ErrorFile);
  267.         process_get(0,fd,"GET",error_doc,arguments);
  268.     } else {
  269.         if(!assbackwards) {
  270.         begin_http_header(fd,StatLine401);
  271.         fprintf(fd,"Content-type: text/html%c",LF);
  272.         fprintf(fd,"WWW-Authenticate: %s%c%c",err_string,LF,LF);
  273.         }
  274.         if(header_only) break;
  275.         title_html(fd,"Authorization Required");
  276.         fprintf(fd,"Browser not authentication-capable or %c",LF);
  277.         fprintf(fd,"authentication failed.%c",LF);
  278.             fprintf(fd,"</BODY>%c",LF);
  279.     }
  280.         break;
  281.       case BAD_REQUEST:
  282.         status = 400;
  283.     if (((x=have_error(type)) >= 0) && (!ErrorStat)) {
  284.         ErrorStat = status;
  285.         strcpy(error_doc,Errors[x].ErrorFile);
  286.         process_get(0,fd,"GET",error_doc,arguments);
  287.     } else {
  288.         error_head(fd,StatLine400);
  289.         if(header_only) break;
  290.         fprintf(fd,"Your client sent a query that this server could not%c",LF);
  291.         fprintf(fd,"understand.<P>%c",LF);
  292.         fprintf(fd,"Reason: %s<P>%c",err_string,LF);
  293.             fprintf(fd,"</BODY>%c",LF);
  294.     }
  295.     break;
  296.       case FORBIDDEN:
  297.         status = 403;
  298.     if (((x=have_error(type)) >= 0) && (!ErrorStat)) {
  299.         ErrorStat = status;
  300.         strcpy(error_doc,Errors[x].ErrorFile);
  301.         process_get(0,fd,"GET",error_doc,arguments);
  302.     } else {
  303.         error_head(fd,StatLine403);
  304.         if(header_only) break;
  305.         fprintf(fd,"Your client does not have permission to get URL %s ",
  306.             err_string);
  307.         fprintf(fd,"from this server.<P>%c",LF);
  308.             fprintf(fd,"</BODY>%c",LF);
  309.     }
  310.     break;
  311.       case NOT_FOUND:
  312.         status = 404;
  313.     if (((x=have_error(type)) >= 0) && (!ErrorStat)) {
  314.         ErrorStat = status;
  315.         strcpy(error_doc,Errors[x].ErrorFile);
  316.         process_get(0,fd,"GET",error_doc,arguments);
  317.     } else {
  318.         error_head(fd,StatLine404);
  319.         if(header_only) break;
  320.         fprintf(fd,"The requested URL %s was not found on this server.<P>%c",
  321.             err_string,LF);
  322.             fprintf(fd,"</BODY>%c",LF);
  323.     }
  324.         break;
  325.       case SERVER_ERROR:
  326.         status = 500;
  327.     if (((x=have_error(type)) >= 0) && (!ErrorStat)) {
  328.         ErrorStat = status;
  329.         strcpy(error_doc,Errors[x].ErrorFile);
  330.         process_get(0,fd,"GET",error_doc,arguments);
  331.     } else {
  332.         error_head(fd,StatLine500);
  333.         if (standalone)
  334.         log_error_noclose(err_string);
  335.         else log_error(err_string);
  336.         if(header_only) 
  337.         break;
  338.         fprintf(fd,"The server encountered an internal error or%c",LF);
  339.         fprintf(fd,"misconfiguration and was unable to complete your%c",LF);
  340.         fprintf(fd,"request.<P>%c",LF);
  341.         fprintf(fd,"Please contact the server administrator,%c",LF);
  342.         fprintf(fd," %s ",server_admin);
  343.         fprintf(fd,"and inform them of the time the error occurred, and%c",LF);
  344.         fprintf(fd,"anything you might have done that may have caused%c",LF);
  345.         fprintf(fd,"the error.<P>%c",LF);
  346.             fprintf(fd,"</BODY>%c",LF);
  347.     }
  348.         break;
  349.       case NOT_IMPLEMENTED:
  350.         status = 501;
  351.     if (((x=have_error(type)) >= 0) && (!ErrorStat)) {
  352.         ErrorStat = status;
  353.         strcpy(error_doc,Errors[x].ErrorFile);
  354.         process_get(0,fd,"GET",error_doc,arguments);
  355.     } else {
  356.         error_head(fd,StatLine501);
  357.         if(header_only) break;
  358.         fprintf(fd,"We are sorry to be unable to perform the method %s",
  359.             err_string);
  360.         fprintf(fd," at this time.<P>%c",LF);
  361.         fprintf(fd,"If you would like to see this capability in future%c",LF);
  362.         fprintf(fd,"releases, send the method which failed, why you%c",LF);
  363.         fprintf(fd,"would like to have it, and the server version %s%c",
  364.             SERVER_VERSION,LF);
  365.         fprintf(fd,"to <ADDRESS>%s</ADDRESS><P>%c",SERVER_SUPPORT,LF);
  366.             fprintf(fd,"</BODY>%c",LF);
  367.     }
  368.         break;
  369.       case NO_MEMORY:
  370.         log_error("httpd: memory exhausted");
  371.         status = 500;
  372.     if (((x=have_error(type)) >= 0) && (!ErrorStat)) {
  373.         ErrorStat = status;
  374.         strcpy(error_doc,Errors[x].ErrorFile);
  375.         process_get(0,fd,"GET",error_doc,arguments);
  376.     } else {
  377.         error_head(fd,StatLine500);
  378.         if(header_only) break;
  379.         fprintf(fd,"The server has temporarily run out of resources for%c",LF);
  380.         fprintf(fd,"your request. Please try again at a later time.<P>%c",LF);
  381.             fprintf(fd,"</BODY>%c",LF);
  382.     }
  383.     break;
  384.       case CONF_ERROR:
  385.     sprintf(arguments,"httpd: configuration error = %s",err_string);
  386.     log_error(arguments);
  387.     error_head(fd,StatLine500);
  388.     if (!header_only) {
  389.       fprintf(fd,"The server has encountered a misconfiguration.%c",LF);
  390.       fprintf(fd,"The error was %s.%c",err_string,LF);
  391.           fprintf(fd,"</BODY>%c",LF);
  392.         }
  393.     }
  394.     fflush(fd);
  395.     log_transaction();
  396.     if (!RetVal) 
  397.       htexit(1,fd);
  398.      else return RetVal;
  399. }
  400.  
  401.  
  402. /* Add error to error table.  Should be called from http_config.c at startup */
  403. int add_error(char* errornum, char* name) {
  404.     char *tmp;
  405.  
  406.     tmp = (char *)malloc(strlen(name)+1);
  407.     strcpy(tmp,name);
  408.     
  409. /*    Errors[numErrorsDefined].Type = type; */
  410.     Errors[numErrorsDefined].ErrorNum = atoi(errornum);
  411.     Errors[numErrorsDefined].ErrorFile = tmp;
  412.  
  413.     return ++numErrorsDefined;
  414. }
  415.  
  416. /* Do we have a defined error for errornum? */
  417. int have_error(int errornum) {
  418.     int x=0;
  419.  
  420.     while ((x < numErrorsDefined) && (Errors[x].ErrorNum != errornum)) {
  421.     x++;}
  422.  
  423.     if (Errors[x].ErrorNum == errornum) return x;
  424.     else return -1;
  425. }
  426.  
  427. /* Reset Error Types (for SIGHUP-restart) */
  428. void reset_error() {
  429.     int x=0;
  430.  
  431.     for (x = 0 ; x < numErrorsDefined ; x++) {
  432.       free(Errors[x].ErrorFile);
  433.       Errors[x].ErrorNum = 0;
  434.     }
  435.  
  436.     numErrorsDefined = 0;
  437. }
  438.